package graph;

import java.util.*;
import java.util.Scanner;

/**
 * 卡99.岛屿数量
 * 题目描述
 * 给定一个由 1（陆地）和 0（水）组成的矩阵，你需要计算岛屿的数量。岛屿由水平方向或垂直方向上相邻的陆地连接而成，并且四周都是水域。你可以假设矩阵外均被水包围。
 * 输入描述
 * 第一行包含两个整数 N, M，表示矩阵的行数和列数。
 * 后续 N 行，每行包含 M 个数字，数字为 1 或者 0。
 * 输出描述
 * 输出一个整数，表示岛屿的数量。如果不存在岛屿，则输出 0。
 */
public class islandcount {

    class dfs {
        public static int[][] dir = {{0, 1}, {1, 0}, {-1, 0}, {0, -1}};

        public static void dfs(boolean[][] visited, int x, int y, int[][] graph) {
            for (int i = 0; i < 4; i++) {
                int nextX = x + dir[i][0];
                int nextY = y + dir[i][1];
                if (nextX < 0 || nextY < 0 || nextX >= graph.length || nextY >= graph[0].length) continue;
                if (!visited[nextX][nextY] && graph[nextX][nextY] == 1) {
                    visited[nextX][nextY] = true;
                    dfs(visited, nextX, nextY, graph);
                }
            }
        }

        public static void main(String[] args) {
            Scanner sc = new Scanner(System.in);
            int n = sc.nextInt();
            int m = sc.nextInt();
            int[][] graph = new int[n][m];
            for (int i = 0; i < n; i++) {
                for (int j = 0; j < m; j++) {
                    graph[i][j] = sc.nextInt();
                }
            }
            boolean[][] visited = new boolean[n][m];
            int res = 0;
            for (int i = 0; i < n; i++) {
                for (int j = 0; j < m; j++) {
                    if (!visited[i][j] && graph[i][j] == 1) {
                        res++;
                        visited[i][j] = true;
                        dfs(visited, i, j, graph);
                    }
                }
            }
            System.out.println(res);
        }
    }


    class bfs {
        public static int[][] dir = {{0, 1}, {1, 0}, {0, -1}, {-1, 0}};//下右上左逆时针遍历

        public static void bfs(int[][] grid, boolean[][] visited, int x, int y) {
            Queue<int[]> queue = new LinkedList<>();//定义坐标队列，没有现成的pair类，在下面自定义了
            queue.add(new int[]{x, y});
            visited[x][y] = true;//遇到入队直接标记为优先，
            // 否则出队时才标记的话会导致重复访问，比如下方节点会在右下顺序的时候被第二次访问入队
            while (!queue.isEmpty()) {
                int[] current = queue.poll(); // 从队列中获取当前坐标
                int curX = current[0]; // 获取 X 坐标
                int curY = current[1]; // 获取 Y 坐标
                for (int i = 0; i < 4; i++) {
                    //顺时针遍历新节点next，下面记录坐标
                    int nextX = curX + dir[i][0];
                    int nextY = curY + dir[i][1];
                    if (nextX < 0 || nextX >= grid.length || nextY < 0 || nextY >= grid[0].length) {
                        continue;
                    }//去除越界部分
                    if (!visited[nextX][nextY] && grid[nextX][nextY] == 1) {
                        queue.add(new int[]{nextX, nextY});
                        visited[nextX][nextY] = true;//逻辑同上
                    }
                }
            }
        }

        public static void main(String[] args) {
            Scanner sc = new Scanner(System.in);
            int m = sc.nextInt();
            int n = sc.nextInt();
            int[][] grid = new int[m][n];
            boolean[][] visited = new boolean[m][n];
            int ans = 0;
            for (int i = 0; i < m; i++) {
                for (int j = 0; j < n; j++) {
                    grid[i][j] = sc.nextInt();
                }
            }
            for (int i = 0; i < m; i++) {
                for (int j = 0; j < n; j++) {
                    if (!visited[i][j] && grid[i][j] == 1) {
                        ans++;
                        bfs(grid, visited, i, j);
                    }
                }
            }
            System.out.println(ans);
        }
    }

    /**
     * 二刷
     */
    class Main {

        static int[][] dir = {{0, 1}, {1, 0}, {0, -1}, {-1, 0}};

        public static void main(String[] args) {
            Scanner sc = new Scanner(System.in);
            int n = sc.nextInt();
            int m = sc.nextInt();
            int[][] graph = new int[n][m];
            for (int i = 0; i < n; i++) {
                for (int j = 0; j < m; j++) {
                    graph[i][j] = sc.nextInt();
                }
            }
            boolean[][] visited = new boolean[n][m];
            int res = 0;
            for (int i = 0; i < n; i++) {
                for (int j = 0; j < m; j++) {
                    if (!visited[i][j] && graph[i][j] == 1) {
                        res++;
                        visited[i][j] = true;
                        dfs(visited, i, j, graph);
                    }
                }
            }
            System.out.println(res);
        }

        public static void dfs(boolean[][] visited, int x, int y, int[][] graph) {
            for (int i = 0; i < 4; i++) {
                int nextX = x + dir[i][0];
                int nextY = y + dir[i][1];
                if (nextX < 0 || nextX >= graph.length || nextY < 0 || nextY >= graph[0].length) continue;
                if (!visited[nextX][nextY] && graph[nextX][nextY] == 1) {
                    visited[nextX][nextY] = true;
                    dfs(visited, nextX, nextY, graph);
                }
            }
        }
    }
}
